home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / osi / isode / dosisode / DOSISODE80.ZIP / ISODE8.WRK / FTAM2 / FTAMUSER.C_N < prev    next >
Encoding:
Text File  |  1992-06-28  |  30.3 KB  |  1,414 lines

  1. /* ftamuser.c - FTAM initiator routines */
  2.  
  3. #ifndef    lint
  4. static char *rcsid = "$Header: /xtel/isode/isode/ftam2/RCS/ftamuser.c,v 9.0 1992/06/16 12:15:43 isode Rel $";
  5. #endif
  6.  
  7. /* 
  8.  * $Header: /xtel/isode/isode/ftam2/RCS/ftamuser.c,v 9.0 1992/06/16 12:15:43 isode Rel $
  9.  *
  10.  *
  11.  * $Log: ftamuser.c,v $
  12.  * Revision 9.0  1992/06/16  12:15:43  isode
  13.  * Release 8.0
  14.  *
  15.  */
  16.  
  17. /*
  18.  *                  NOTICE
  19.  *
  20.  *    Acquisition, use, and distribution of this module and related
  21.  *    materials are subject to the restrictions of a license agreement.
  22.  *    Consult the Preface in the User's Manual for the full terms of
  23.  *    this agreement.
  24.  *
  25.  */
  26.  
  27.  
  28. #include <ctype.h>
  29. #include <errno.h>
  30. #include <stdio.h>
  31. #include "ftamuser.h"
  32. #include "tailor.h"
  33. #if    defined(SYS5) && !defined(HPUX)
  34. #include <sys/times.h>
  35. #define    TMS
  36. #endif
  37. #ifdef    BSD42
  38. #include <sys/ioctl.h>
  39. #endif
  40.  
  41. /*     DATA */
  42.  
  43. int   ftamfd = NOTOK;
  44.  
  45. char *host = NULLCP;
  46. char *user = NULLCP;
  47. char *account = NULLCP;
  48. #ifndef    BRIDGE
  49. char *userdn = NULLCP;
  50. char *storename = NULLCP;
  51. #endif
  52.  
  53. int   bell = 0;
  54. int   concurrency = 1;
  55. #ifndef    BRIDGE
  56. int   debug = 0;
  57. #endif
  58. #ifdef    BRIDGE
  59. int   globbing = 1;
  60. #else
  61. int   globbing = 0;
  62. #endif
  63. int   hash = 0;
  64. int   marks = 0;
  65. int   omode = FOVER_WRITE;
  66. int   query = 1;
  67. int   runcom = 0;
  68. #ifdef    BRIDGE
  69. int   tmode = VFS_UTF;
  70. #else
  71. int   tmode = VFS_DEF;
  72. #endif
  73. int   trace = 0;
  74. #ifndef    BRIDGE
  75. int   verbose = 0;
  76. int   watch = 0;
  77. #endif
  78.  
  79.  
  80. char *myuser = NULLCP;
  81. char *myhome = NULLCP;
  82.  
  83. #ifdef    BRIDGE
  84. int realstore = RFS_UNIX;
  85. #else
  86. int realstore = 0;
  87. #endif
  88.  
  89. char *rs_unknown =
  90.     "type of remote realstore is unknown; use \"set realstore\"";
  91. char *rs_support = "operation not supported on remote realstore";
  92.  
  93.  
  94. char *rcwd = NULL;
  95.  
  96. #ifdef    BRIDGE
  97. int    ftp_default = VFS_UTF;
  98. int    ftp_directory;
  99. char    ftam_error[BUFSIZ];
  100. #endif
  101.  
  102. struct QOStype myqos;
  103.  
  104. /*     DISPATCH */
  105.  
  106. #ifndef    BRIDGE
  107. int    f_open (), f_close (), f_quit (), f_status ();
  108. int    f_set (), f_help ();
  109. int    f_lcd (), f_cd (), f_pwd ();
  110. int    f_ls (), f_fls ();
  111. int    f_get (), f_put ();
  112. int    f_mv (), f_rm (), f_chgrp (), f_mkdir ();
  113. int    f_echo ();
  114.  
  115.  
  116. static struct dispatch  dispatches[] = {
  117.     "append", f_put, DS_OPEN | DS_MODES, FCLASS_TRANSFER, FUNIT_WRITE,
  118.     "append to a file in the virtual filestore",
  119.  
  120.     "cd", f_cd, DS_OPEN, 0, 0,
  121.     "change working directory on virtual filestore",
  122.  
  123.     "chgrp", f_chgrp, DS_OPEN | DS_MODES, FCLASS_MANAGE, FUNIT_ENHANCED,
  124.     "change group of a file",
  125.  
  126.     "close", f_close, DS_OPEN, 0, 0,
  127.     "terminate association with virtual filestore",
  128.  
  129.     "dir", f_ls, DS_OPEN | DS_MODES, FCLASS_MANAGE, FUNIT_LIMITED,
  130.     "print long directory listing",
  131.  
  132.     "echo", f_echo, DS_OPEN | DS_MODES, FCLASS_MANAGE, FUNIT_LIMITED,
  133.     "echo globbed filenames",
  134.  
  135.     "fdir", f_fls, DS_OPEN | DS_MODES, FCLASS_MANAGE, FUNIT_LIMITED,
  136.     "print long directory listing to a file/program",
  137.  
  138.     "fls", f_fls, DS_OPEN | DS_MODES, FCLASS_MANAGE, FUNIT_LIMITED,
  139.     "print directory listing to a file/program",
  140.  
  141.     "get", f_get, DS_OPEN | DS_MODES, FCLASS_TRANSFER, FUNIT_READ,
  142.     "retrieve file",
  143.  
  144.     "help", f_help, DS_NULL, 0, 0,
  145.     "print help information",
  146.  
  147.     "lcd", f_lcd, DS_NULL, 0, 0,
  148.     "change working directory on local system",
  149.  
  150.     "ls", f_ls, DS_OPEN | DS_MODES, FCLASS_MANAGE, FUNIT_LIMITED,
  151.     "print directory listing",
  152.  
  153.     "mkdir", f_mkdir, DS_OPEN | DS_MODES, FCLASS_MANAGE, FUNIT_LIMITED,
  154.     "create directory",
  155.  
  156.     "mv", f_mv, DS_OPEN | DS_MODES, FCLASS_MANAGE, FUNIT_ENHANCED,
  157.     "rename file",
  158.  
  159.     "open", f_open, DS_CLOSE, 0, 0,
  160.     "associate with virtual filestore",
  161.  
  162.     "put", f_put, DS_OPEN | DS_MODES, FCLASS_TRANSFER, FUNIT_WRITE,
  163.     "store file",
  164.  
  165.     "pwd", f_pwd, DS_NULL, 0, 0,
  166.     "print working directories",
  167.  
  168.     "quit", f_quit, DS_NULL, 0, 0,
  169.     "terminate association with virtual filestore and exit",
  170.  
  171.     "rm", f_rm, DS_OPEN | DS_MODES, FCLASS_MANAGE, FUNIT_LIMITED,
  172.     "delete file",
  173.  
  174.     "set", f_set, DS_NULL, 0, 0,
  175.     "display or change variables",
  176.  
  177.     "status", f_status, DS_OPEN, 0, 0,
  178.     "show current status",
  179.  
  180.     NULL
  181. };
  182.  
  183. /*   */
  184.  
  185. struct dispatch *getds (name)
  186. register char *name;
  187. {
  188.     register int    longest,
  189.                     nmatches;
  190.     register char  *p,
  191.                    *q;
  192.     char    buffer[BUFSIZ];
  193.     register struct dispatch   *ds,
  194.                                *fs;
  195.  
  196.     longest = nmatches = 0;
  197.     for (ds = dispatches; p = ds -> ds_name; ds++) {
  198.     for (q = name; *q == *p++; q++)
  199.         if (*q == NULL)
  200.         return ds;
  201.     if (*q == NULL)
  202.         if (q - name > longest) {
  203.         longest = q - name;
  204.         nmatches = 1;
  205.         fs = ds;
  206.         }
  207.         else
  208.         if (q - name == longest)
  209.             nmatches++;
  210.     }
  211.  
  212.     switch (nmatches) {
  213.     case 0: 
  214.         advise (NULLCP, "unknown operation \"%s\"", name);
  215.         return NULL;
  216.  
  217.     case 1: 
  218.         return fs;
  219.  
  220.     default: 
  221.         for (ds = dispatches, p = buffer; q = ds -> ds_name; ds++)
  222.         if (strncmp (q, name, longest) == 0) {
  223.             (void) sprintf (p, "%s \"%s\"", p != buffer ? "," : "", q);
  224.             p += strlen (p);
  225.         }
  226.         advise (NULLCP, "ambiguous operation, it could be one of:%s",
  227.             buffer);
  228.         return NULL;
  229.     }
  230. }
  231. #endif
  232.  
  233. /*     VARIABLES */
  234.  
  235. #ifndef    BRIDGE
  236. static char *bool[] = {
  237.     "off", "on", NULL
  238. };
  239.  
  240. static char *hmodes[] = {
  241.     "off", "on", "total", NULL
  242. };
  243.  
  244. static char *omodes[] = {
  245.     "fail", "select", "write", "delete", NULL
  246. };
  247.  
  248. static char *tmodes[] = {
  249.     "default", "binary", "text", NULL
  250. };
  251.  
  252. static char *realstores[] = {
  253.     "unknown", "unix", NULL
  254. };
  255.  
  256. static char *xsaplevels[] = {
  257.     "none", "fatal", "exceptions", "notice", "pdus", "trace", "debug", NULL
  258. };
  259.  
  260.  
  261. static char *sversions[] = {
  262.     "default", "v1", "v2", NULL
  263. };
  264.  
  265.  
  266. struct var {
  267.     char   *v_name;
  268.     IP        v_value;
  269.  
  270.     char   *v_dname;
  271.     char  **v_dvalue;
  272.     char   *v_mask;
  273.  
  274.     IFP        v_hook;
  275. };
  276.  
  277. struct var *getvar ();
  278.  
  279.  
  280. int    set_realstore (), set_trace (), set_type (), set_prompt();
  281.  
  282. /* prompt stuff */
  283. # define DEFAULT_PROMPT     "%s> "
  284. # define DEFAULT_PROMPT_STR    "default"
  285. char     *command_prompt = DEFAULT_PROMPT;
  286. char    *var_prompt = DEFAULT_PROMPT_STR;
  287.  
  288. static struct var vars[] = {
  289.     "acsaplevel", &_acsap_log.ll_events, "ACSAP logging", xsaplevels,
  290.     LLOG_MASK, NULLIFP,
  291.     "acsapfile", NULLIP, "ACSAP trace file", &_acsap_log.ll_file, NULLCP,
  292.     NULLIFP,
  293.  
  294.     "addrlevel", &_addr_log.ll_events, "address logging", xsaplevels,
  295.     LLOG_MASK, NULLIFP,
  296.     "addrfile", NULLIP, "address trace file", &_addr_log.ll_file, NULLCP,
  297.     NULLIFP,
  298.  
  299.     "bell", &bell, "ring the bell when a command finishes", bool, NULLCP,
  300.     NULLIFP,
  301.  
  302.     "compatlevel", &_compat_log.ll_events, "COMPAT logging", xsaplevels,
  303.     LLOG_MASK, NULLIFP,
  304.     "compatfile", NULLIP, "COMPAT trace file", &_compat_log.ll_file, NULLCP,
  305.     NULLIFP,
  306.  
  307.     "concurrency", &concurrency,    /* Olivier Dubois */
  308.     "request concurrency control for transfers", bool, NULLCP, NULLIFP,
  309.  
  310.     "debug", &debug, "debug FTAM", bool, NULLCP, NULLIFP,
  311.  
  312.     "glob", &globbing, "expand metacharacters like the shell", bool, NULLCP,
  313.     NULLIFP,
  314.  
  315.     "hash", &hash, "hash mark printing", hmodes, NULLCP, NULLIFP,
  316.  
  317.     "override", &omode, "creation override mode", omodes, NULLCP, NULLIFP,
  318.  
  319.     "prompt", NULLIP, "command prompt string", &var_prompt, NULLCP, 
  320.         set_prompt, 
  321.  
  322.     "psaplevel", &_psap_log.ll_events, "PSAP logging", xsaplevels,
  323.     LLOG_MASK, NULLIFP,
  324.     "psapfile", NULLIP, "PSAP trace file", &_psap_log.ll_file, NULLCP,
  325.     NULLIFP,
  326.  
  327.     "psap2level", &_psap2_log.ll_events, "PSAP2 logging", xsaplevels,
  328.     LLOG_MASK, NULLIFP,
  329.     "psap2file", NULLIP, "PSAP2 trace file", &_psap2_log.ll_file, NULLCP,
  330.     NULLIFP,
  331.  
  332.     "qualifier", NULLIP, "service qualifier", &storename, NULLCP, NULLIFP,
  333.  
  334.     "query", &query, "confirm operations on globbing", bool, NULLCP, NULLIFP,
  335.  
  336.     "realstore", &realstore, "type of remote realstore", realstores, NULLCP,
  337.     set_realstore,
  338.  
  339.     "ssaplevel", &_ssap_log.ll_events, "SSAP logging", xsaplevels,
  340.     LLOG_MASK, NULLIFP,
  341.     "ssapfile", NULLIP, "SSAP trace file", &_ssap_log.ll_file, NULLCP,
  342.     NULLIFP,
  343.  
  344.     "sversion", &myqos.qos_sversion, "session version number", sversions,
  345.     NULLCP, NULLIFP,
  346.  
  347.     "trace", &trace, "trace FPDUs", bool, NULLCP, set_trace,
  348.     "tracefile", NULLIP, "FTAM trace file", &_ftam_log.ll_file, NULLCP,
  349.     NULLIFP,
  350.  
  351.     "tsaplevel", &_tsap_log.ll_events, "TSAP logging", xsaplevels,
  352.     LLOG_MASK, NULLIFP,
  353.     "tsapfile", NULLIP, "TSAP trace file", &_tsap_log.ll_file, NULLCP,
  354.     NULLIFP,
  355.  
  356.     "type", &tmode, "file transfer mode", tmodes, NULLCP, set_type,
  357.  
  358.     "verbose", &verbose, "verbose interaction", bool, NULLCP, NULLIFP,
  359.  
  360.     "userdn", NULLIP, "DN to use when binding for AE-lookup", &userdn, NULLCP,
  361.     NULLIFP,
  362.  
  363.     "watch", &watch, "watch transfers", bool, NULLCP, NULLIFP,
  364.  
  365.     NULL
  366. };
  367.  
  368.  
  369. static int varwidth1;
  370. static int varwidth2;
  371.  
  372. char    **getval ();
  373.  
  374. /*   */
  375.  
  376. static int  f_set (vec)
  377. char  **vec;
  378. {
  379.     register int    i,
  380.             j;
  381.     int     value,
  382.         vflag;
  383.     register char **cp,
  384.            *dp;
  385.     register struct var *v;
  386.  
  387.     if (*++vec == NULL) {
  388.     register int    w;
  389.     int     columns,
  390.         width,
  391.         lines;
  392.     register struct var *u;
  393.  
  394.     for (u = vars; u -> v_name; u++)
  395.         continue;
  396.     width = varwidth1;
  397.  
  398.     if ((columns = ncols (stdout) / (width = (width + 8) & ~7)) == 0)
  399.         columns = 1;
  400.     lines = ((u - vars) + columns - 1) / columns;
  401.  
  402.     (void) printf ("Variables:\n");
  403.     for (i = 0; i < lines; i++)
  404.         for (j = 0; j < columns; j++) {
  405.         v = vars + j * lines + i;
  406.         (void) printf ("%s", v -> v_name);
  407.         if (v + lines >= u) {
  408.             (void) printf ("\n");
  409.             break;
  410.         }
  411.         for (w = strlen (v -> v_name); w < width; w = (w + 8) & ~7)
  412.             (void) putchar ('\t');
  413.         }
  414.  
  415.     return OK;
  416.     }
  417.  
  418.     if (strcmp (*vec, "?") == 0) {
  419.     for (v = vars; v -> v_name; v++)
  420.         printvar (v);
  421.  
  422.     return OK;
  423.     }
  424.  
  425.     if ((v = getvar (*vec)) == NULL)
  426.     return OK;
  427.  
  428.     if (*++vec == NULL) {
  429.     printvar (v);
  430.  
  431.     return OK;
  432.     }
  433.  
  434.     if (strcmp (*vec, "?") == 0) {
  435.     if (v -> v_value && (cp = v -> v_dvalue)) {
  436.         (void) printf ("use %s of:", v -> v_mask ? "any" : "one");
  437.         for (i = 0; *cp; cp++)
  438.         (void) printf ("%s \"%s\"", i++ ? "," : "", *cp);
  439.         if (v -> v_mask)
  440.         (void) printf (";\n\tor  \"all\";\n\tor a hexadecimal number from 0 to 0x%x\n",
  441.             (1 << (i - 1)) - 1);
  442.         else
  443.         (void) printf (";\n\tor a number from 0 to %d\n",
  444.             cp - v -> v_dvalue - 1);
  445.     }
  446.     else
  447.         (void) printf ("use any %s value\n",
  448.             v -> v_value ? "integer" : "string");
  449.  
  450.     return OK;
  451.     }
  452.  
  453.     if (v -> v_value == NULLIP) {
  454.     register int    w;
  455.  
  456.     if (*v -> v_dvalue)
  457.         free (*v -> v_dvalue);
  458.     *v -> v_dvalue = strdup (*vec);
  459.     if ((w = strlen (*v -> v_dvalue) + 2) > varwidth2)
  460.         varwidth2 = w;
  461.     if (v -> v_hook)
  462.         (*v -> v_hook) (v);
  463.     if (verbose)
  464.         printvar (v);
  465.     return OK;
  466.     }
  467.  
  468.     if (v -> v_mask) {
  469.     if (strcmp (dp = *vec, "all") == 0 && (cp = v -> v_dvalue)) {
  470.         i = 1;
  471.         while (*++cp)
  472.         i <<= 1;
  473.         value = i - 1;
  474.         j = 1;
  475.     }
  476.     else {
  477.         if (strncmp (dp, "0x", 2) == 0)
  478.         dp += 2;
  479.         for (j = sscanf (dp, "%x", &value); *dp; dp++)
  480.         if (!isxdigit ((u_char) *dp)) {
  481.             j = 0;
  482.             break;
  483.         }
  484.     }
  485.     }
  486.     else
  487.     j = sscanf (*vec, "%d", &value);
  488.  
  489.     if (j == 1) {
  490.     if (cp = v -> v_dvalue) {
  491.         if (v -> v_mask) {
  492.         i = 1;
  493.         while (*++cp)
  494.             i <<= 1;
  495.         if (value >= i)
  496.             goto out_of_range;
  497.         }
  498.         else {
  499.         for (; *cp; cp++)
  500.             continue;
  501.         if (value >= cp - v -> v_dvalue) {
  502. out_of_range: ;
  503.             advise (NULLCP, "value out of range \"%s\"", *vec);
  504.  
  505.             return OK;
  506.         }
  507.         }
  508.     }
  509.  
  510.     vflag = verbose;
  511.     *v -> v_value = value;
  512.     if (v -> v_hook)
  513.         (*v -> v_hook) (v);
  514.     if (vflag)
  515.         printvar (v);
  516.  
  517.     return OK;
  518.     }
  519.  
  520.     if (v -> v_mask) {
  521.     i = 0;
  522.     for (; *vec; vec++) {
  523.         if (!(cp = getval (*vec, v -> v_dvalue))) {
  524.         advise (NULLCP, "bad value \"%s\"", *vec);
  525.  
  526.         return OK;
  527.         }
  528.         if ((j = cp - v -> v_dvalue) <= 0)
  529.         continue;
  530.  
  531.         i |= 1 << (j - 1);
  532.     }
  533.  
  534.     vflag = verbose;
  535.     *v -> v_value = i;
  536.     if (v -> v_hook)
  537.         (*v -> v_hook) (v);
  538.     if (vflag)
  539.         printvar (v);
  540.  
  541.     return OK;
  542.     }
  543.  
  544.     if (v -> v_dvalue && (cp = getval (*vec, v -> v_dvalue))) {
  545.     vflag = verbose;
  546.     *v -> v_value = cp - v -> v_dvalue;
  547.     if (v -> v_hook)
  548.         (*v -> v_hook) (v);
  549.     if (vflag)
  550.         printvar (v);
  551.     }
  552.     else
  553.     if (!v -> v_dvalue)
  554.         advise (NULLCP, "bad value \"%s\"", *vec);
  555.  
  556.     return OK;
  557. }
  558.  
  559. /*   */
  560.  
  561. static printvar (v)
  562. register struct var *v;
  563. {
  564.     int        i;
  565.     char    buffer[BUFSIZ];
  566.  
  567.     if (runcom)
  568.     return;
  569.  
  570.     (void) printf ("%-*s = ", varwidth1, v -> v_name);
  571.     if (v -> v_value) {
  572.     i = *v -> v_value;
  573.  
  574.     if (v -> v_mask) {
  575.         if (v -> v_dvalue) {
  576.         if (i == 0)
  577.             (void) printf ("%-*s", varwidth2, v -> v_dvalue[i]);
  578.         else {
  579.             (void) strcpy (buffer, sprintb (i, v -> v_mask));
  580.             if ((int)strlen (buffer) <= varwidth2)
  581.             (void) printf ("%-*s", varwidth2, buffer);
  582.             else
  583.             (void) printf ("%s\n%*s", buffer, varwidth1 + varwidth2 + 3,
  584.                 "");
  585.         }
  586.         }
  587.         else
  588.         (void) printf ("0x%-*x", varwidth2 - 2, i);
  589.     }
  590.     else {
  591.         if (v -> v_dvalue)
  592.         (void) printf ("%-*s", varwidth2, v -> v_dvalue[i]);
  593.         else
  594.         (void) printf ("%-*d", varwidth2, i);
  595.     }
  596.     }
  597.     else
  598.     if (*v -> v_dvalue) {
  599.         (void) sprintf (buffer, "\"%s\"", *v -> v_dvalue);
  600.         (void) printf ("%-*s", varwidth2, buffer);
  601.     }
  602.     (void) printf ("    - %s\n", v -> v_dname);
  603. }
  604.  
  605. /*   */
  606.  
  607. /* ARGSUSED */
  608.  
  609. char*
  610. default_prompt()
  611. {
  612.     return(DEFAULT_PROMPT);
  613. }
  614.  
  615.  
  616. static int set_prompt(v)
  617. struct var *v;
  618. {
  619.     char    *new = *(v->v_dvalue);
  620.  
  621.     if(!new || !lexequ(new, DEFAULT_PROMPT_STR)) {
  622.     command_prompt = default_prompt();
  623.     } else {
  624.     command_prompt = new;
  625.     }
  626. }
  627.  
  628.  
  629. static int  set_realstore (v)
  630. struct var *v;
  631. {
  632.     char   *vec[2];
  633.  
  634.     if (ftamfd != NOTOK) {
  635.     vec[0] = "sd";
  636.     vec[1] = NULLCP;
  637.  
  638.     (void) f_cd (vec);
  639.     }
  640. }
  641.  
  642.  
  643.  
  644. /* ARGSUSED */
  645.  
  646. static int  set_trace (v)
  647. struct var *v;
  648. {
  649.     struct FTAMindication   ftis;
  650.     register struct FTAMindication *fti = &ftis;
  651.  
  652.     if (ftamfd == NOTOK)
  653.     return;
  654.  
  655.     if (FHookRequest (ftamfd, trace ? FTraceHook : NULLIFP, fti) == NOTOK)
  656.     ftam_advise (&fti -> fti_abort, "F-HOOK.REQUEST");
  657. }
  658.  
  659.  
  660. /* ARGSUSED */
  661.  
  662. static int  set_type (v)
  663. struct var *v;
  664. {
  665.     register struct vfsmap *vf;
  666.  
  667.     if (tmode == VFS_DEF) _fmode = O_TEXT; /*change the default - pkay*/
  668.     if (tmode == VFS_UTF) _fmode = O_TEXT; /*change the default - pkay*/
  669.     if (tmode == VFS_UBF) _fmode = O_BINARY; /*change the default - pkay*/
  670.     if (ftamfd == NOTOK)
  671.     return;
  672.  
  673.     if ((vf = &vfs[tmode]) != &vfs[VFS_DEF]
  674.         && (vf -> vf_oid == NULLOID || !(vf -> vf_flags & VF_OK))) {
  675.     advise (NULLCP, "negotiation prevents transfer of %ss",
  676.         vf -> vf_text);
  677.  
  678.     tmode = VFS_DEF;
  679.     _fmode = O_TEXT; /*change the default - pkay*/
  680.     }
  681. }
  682.  
  683. /*   */
  684.  
  685. static char **getval (name, choices)
  686. register char *name;
  687. char   **choices;
  688. {
  689.     register int    longest,
  690.                     nmatches;
  691.     register char  *p,
  692.                    *q,
  693.                   **cp,
  694.                   **fp;
  695.     char    buffer[BUFSIZ];
  696.  
  697.     longest = nmatches = 0;
  698.     for (cp = choices; p = *cp; cp++) {
  699.     for (q = name; *q == *p++; q++)
  700.         if (*q == NULL)
  701.         return cp;
  702.     if (*q == NULL)
  703.         if (q - name > longest) {
  704.         longest = q - name;
  705.         nmatches = 1;
  706.         fp = cp;
  707.         }
  708.         else
  709.         if (q - name == longest)
  710.             nmatches++;
  711.     }
  712.  
  713.     switch (nmatches) {
  714.     case 0: 
  715.         advise (NULLCP, "unknown value \"%s\"", name);
  716.         return NULL;
  717.  
  718.     case 1: 
  719.         return fp;
  720.  
  721.     default: 
  722.         for (cp = choices, p = buffer; q = *cp; cp++)
  723.         if (strncmp (q, name, longest) == 0) {
  724.             (void) sprintf (p, "%s \"%s\"", p != buffer ? "," : "", q);
  725.             p += strlen (p);
  726.         }
  727.         advise (NULLCP, "ambiguous value, it could be one of:%s",
  728.             buffer);
  729.         return NULL;
  730.     }
  731. }
  732.  
  733. /*   */
  734.  
  735. static struct var *getvar (name)
  736. register char *name;
  737. {
  738.     register int    longest,
  739.                     nmatches;
  740.     register char  *p,
  741.                    *q;
  742.     char    buffer[BUFSIZ];
  743.     register struct var *v,
  744.             *f;
  745.  
  746.     longest = nmatches = 0;
  747.     for (v = vars; p = v -> v_name; v++) {
  748.     for (q = name; *q == *p++; q++)
  749.         if (*q == NULL)
  750.         return v;
  751.     if (*q == NULL)
  752.         if (q - name > longest) {
  753.         longest = q - name;
  754.         nmatches = 1;
  755.         f = v;
  756.         }
  757.         else
  758.         if (q - name == longest)
  759.             nmatches++;
  760.     }
  761.  
  762.     switch (nmatches) {
  763.     case 0: 
  764.         advise (NULLCP, "unknown variable \"%s\"", name);
  765.         return NULL;
  766.  
  767.     case 1: 
  768.         return f;
  769.  
  770.     default: 
  771.         for (v = vars, p = buffer; q = v -> v_name; v++)
  772.         if (strncmp (q, name, longest) == 0) {
  773.             (void) sprintf (p, "%s \"%s\"", p != buffer ? "," : "", q);
  774.             p += strlen (p);
  775.         }
  776.         advise (NULLCP, "ambiguous variable, it could be one of:%s",
  777.             buffer);
  778.         return NULL;
  779.     }
  780. }
  781.  
  782. /*     HELP */
  783.  
  784. static int helpwidth;
  785.  
  786. /*   */
  787.  
  788. static int  f_help (vec)
  789. char  **vec;
  790. {
  791.     register int    i,
  792.                     j,
  793.                     w;
  794.     int     columns,
  795.             width,
  796.             lines;
  797.     register struct dispatch   *ds,
  798.                                *es;
  799.  
  800.     for (es = dispatches; es -> ds_name; es++)
  801.     continue;
  802.     width = helpwidth;
  803.  
  804.     if (*++vec == NULL) {
  805.     if ((columns = ncols (stdout) / (width = (width + 8) & ~7)) == 0)
  806.         columns = 1;
  807.     lines = ((es - dispatches) + columns - 1) / columns;
  808.  
  809.     (void) printf ("Operations:\n");
  810.     for (i = 0; i < lines; i++)
  811.         for (j = 0; j < columns; j++) {
  812.         ds = dispatches + j * lines + i;
  813.         (void) printf ("%s", ds -> ds_name);
  814.         if (ds + lines >= es) {
  815.             (void) printf ("\n");
  816.             break;
  817.         }
  818.         for (w = strlen (ds -> ds_name); w < width; w = (w + 8) & ~7)
  819.             (void) putchar ('\t');
  820.         }
  821.  
  822.     (void) printf ("\nversion info:\t%s\n\t\t%s\n", ftamversion, isodeversion);
  823.  
  824.     return OK;
  825.     }
  826.  
  827.     for (; *vec; vec++)
  828.     if (strcmp (*vec, "?") == 0) {
  829.         for (ds = dispatches; ds -> ds_name; ds++)
  830.         (void) printf ("%-*s\t- %s\n", width, ds -> ds_name, ds -> ds_help);
  831.  
  832.         break;
  833.     }
  834.     else
  835.         if (ds = getds (*vec))
  836.         (void) printf ("%-*s\t- %s\n", width, ds -> ds_name, ds -> ds_help);
  837.  
  838.     return OK;
  839. }
  840. #endif
  841.  
  842. /*     FTAM */
  843.  
  844. /* When going from an FADU to an SSDU via FTAM, we are talking about:
  845.  
  846.     octets = 2 + <number of FADUs>*12 + <size of each FADU>
  847.  
  848.    in the best case, and probably
  849.  
  850.     octets = 3 + <number of FADUs>*16 + <size of each FADU>
  851.  
  852.    on the average.  
  853.  
  854.    On a Berkeley UNIX system we typically see a blksize of 8192 octets.
  855.  
  856.    When deciding how to read from the filesystem when writing to the network,
  857.    for the file's FADU size, we prefer to use the integral FADU size,
  858.    unless the blksize is larger.  This works well on LANs.
  859.  */
  860.  
  861. OID    context;
  862. int    fqos;
  863. int    ftam_class = FCLASS_TRANSFER | FCLASS_MANAGE | FCLASS_TM;
  864. int    units;
  865. int    attrs;
  866. int    fadusize;
  867.  
  868.  
  869. struct vfsmap vfs[] = {
  870. /* VFS_DEF */
  871.     "default", NULLOID, NULLCP, VF_NULL, 0, 0, NULLIFP, ' ', VFS_XXX,
  872.     0,
  873.     0, NULLIFP,
  874.            -1,
  875.     NULLCP,
  876.  
  877. /* VFS_UBF */
  878.     "FTAM-3", NULLOID, NULLCP, VF_WARN, 0, S_IFREG, binarypeek, 'b', VFS_XXX,
  879.     FA_ACC_UA,
  880.     1, binarycheck,
  881.        _ZFTAM_3_ParametersDOCS,
  882.     "unstructured binary file",
  883.  
  884. /* VFS_UTF */
  885.     "FTAM-1", NULLOID, NULLCP, VF_WARN, 0, S_IFREG, textpeek, 't', VFS_UBF,
  886.     FA_ACC_UA,
  887.     1, textcheck,
  888.        _ZFTAM_1_ParametersDOCS,
  889.     "unstructured text file",
  890.  
  891. /* VFS_FDF */
  892. #ifdef COMPAT_OLD_NBS9OID
  893.     "NBS-9",  NULLOID, NULLCP, VF_ALIASED, 0, S_IFDIR, fdfpeek, 'd', VFS_XXX,
  894. #else
  895.     "NBS-9",  NULLOID, NULLCP, VF_NULL, 0, S_IFDIR, fdfpeek, 'd', VFS_XXX,
  896. #endif /* COMPAT_OLD_NBS9OID */
  897.     FA_ACC_UA,
  898.     0, NULLIFP,
  899.        _ZNBS_9_ParametersDOCS,
  900.     "file directory file",
  901.  
  902.     NULL
  903. };
  904. #ifdef    BRIDGE
  905. int    vfs_fdf = VFS_FDF;
  906. #endif
  907.  
  908. struct vfsmap *myvf;
  909.  
  910. /*   */
  911.  
  912. void    ftam_advise (fta, event)
  913. register struct FTAMabort *fta;
  914. char   *event;
  915. {
  916.     if (hash && marks >= BUFSIZ) {
  917.     marks = 0;
  918.     (void) printf ("\n");
  919.     }
  920.  
  921.     (void) fflush (stdout);
  922.  
  923.     if (fta -> fta_peer) {
  924. #ifdef    BRIDGE
  925.     (void) sprintf (ftam_error, "%s: peer aborted association, due to ",
  926.             event);
  927. #else
  928.     (void) fprintf (stderr, "%s: peer aborted association, due to ", event);
  929. #endif
  930.     switch (fta -> fta_action) {
  931.         case FACTION_TRANS: 
  932. #ifdef    BRIDGE
  933.         (void) sprintf (ftam_error + strlen (ftam_error),
  934.                 "transient-error");
  935. #else
  936.         (void) fprintf (stderr, "transient-error");
  937. #endif
  938.         break;
  939.  
  940.         case FACTION_PERM: 
  941. #ifdef    BRIDGE
  942.         (void) sprintf (ftam_error + strlen (ftam_error),
  943.                 "permanent-error");
  944. #else
  945.         (void) fprintf (stderr, "permanent-error");
  946. #endif
  947.         break;
  948.  
  949.         default: 
  950. #ifdef    BRIDGE
  951.         (void) sprintf (ftam_error + strlen (ftam_error),
  952.                 "action result %d", fta -> fta_action);
  953. #else
  954.         (void) fprintf (stderr, "action result %d", fta -> fta_action);
  955. #endif
  956.         break;
  957.     }
  958. #ifndef    BRIDGE
  959.     (void) fprintf (stderr, "\n");
  960. #endif
  961.     }
  962.     else
  963. #ifdef    BRIDGE
  964.     (void) sprintf (ftam_error + strlen (ftam_error), "%s: failed\n",
  965.             event);
  966.     if (verbose)
  967.     advise (NULLCP, "%s", ftam_error);
  968. #else
  969.     (void) fprintf (stderr, "%s: failed\n", event);
  970. #endif
  971.     ftam_diag (fta -> fta_diags, fta -> fta_ndiag, fta -> fta_peer,
  972.         FACTION_PERM);
  973.  
  974.     if (fta -> fta_action == FACTION_PERM) {
  975.     ftamfd = NOTOK;
  976.     if (rcwd) {
  977.         free (rcwd);
  978.         rcwd = NULL;
  979.     }
  980.     }
  981. }
  982.  
  983. /*   */
  984.  
  985. void    ftam_chrg (charges)
  986. register struct FTAMcharging *charges;
  987. {
  988.     register int    i;
  989.     char   *cp;
  990.     register struct fc_charge  *fc;
  991.  
  992.     cp = "charging information:\n    %s: %d %s\n";
  993.     for (fc = charges -> fc_charges, i = charges -> fc_ncharge - 1;
  994.         i >= 0;
  995.         fc++, i--, cp = "    %s: %d %s\n")
  996. #ifdef    BRIDGE
  997.     (void) sprintf (ftam_error, cp, fc -> fc_resource, fc -> fc_value,
  998.             fc -> fc_unit);
  999.     advise (NULLCP, "%s", ftam_error);
  1000. #else
  1001.     (void) printf (cp, fc -> fc_resource, fc -> fc_value, fc -> fc_unit);
  1002. #endif
  1003. }
  1004.  
  1005. /*   */
  1006.  
  1007. static char *entity[] = {
  1008.     "unknown",
  1009.     "initiator",
  1010.     "initiator's FPM",
  1011.     "virtual filestore",
  1012.     "responder's FPM",
  1013.     "responder"
  1014. };
  1015.  
  1016.  
  1017. void    ftam_diag (diag, ndiag, peer, action)
  1018. struct FTAMdiagnostic diag[];
  1019. int    ndiag;
  1020. int    peer,
  1021.     action;
  1022. {
  1023.     register int    i;
  1024.     int     didit;
  1025.     register struct FTAMdiagnostic *dp;
  1026.  
  1027. #ifdef    BRIDGE
  1028.     ftam_error[0] = NULL;
  1029. #endif
  1030.     for (dp = diag, i = ndiag - 1; i >= 0; dp++, i--) {
  1031.     if (dp -> ftd_identifier != FS_GEN_NOREASON) {
  1032. #ifdef    BRIDGE
  1033.         (void) sprintf (ftam_error + strlen (ftam_error),
  1034.                 "%s", FErrString (dp -> ftd_identifier));
  1035. #else
  1036.         (void) printf ("%s", FErrString (dp -> ftd_identifier));
  1037. #endif
  1038.         if (dp -> ftd_cc > 0)
  1039. #ifdef    BRIDGE
  1040.         (void) sprintf (ftam_error + strlen (ftam_error),
  1041.                 ": %*.*s", dp -> ftd_cc, dp -> ftd_cc,
  1042.                 dp -> ftd_data);
  1043. #else
  1044.         (void) printf (": %*.*s", dp -> ftd_cc, dp -> ftd_cc, dp -> ftd_data);
  1045. #endif
  1046.     }
  1047.     else
  1048.         if (dp -> ftd_cc > 0)
  1049. #ifdef    BRIDGE
  1050.         (void) sprintf (ftam_error + strlen (ftam_error),
  1051.                 "%*.*s", dp -> ftd_cc, dp -> ftd_cc,
  1052.                 dp -> ftd_data);
  1053. #else
  1054.         (void) printf ("%*.*s", dp -> ftd_cc, dp -> ftd_cc, dp -> ftd_data);
  1055. #endif
  1056.  
  1057. #ifdef    BRIDGE
  1058.     advise (NULLCP, "%s", ftam_error);
  1059. #else
  1060.     (void) printf ("\n");
  1061. #endif
  1062.  
  1063.     didit = 0;
  1064.     switch (dp -> ftd_type) {
  1065.         case DIAG_INFORM: 
  1066.         if (action == FACTION_SUCCESS)
  1067.             break;
  1068.         didit++;
  1069. #ifdef    BRIDGE
  1070.         (void) sprintf (ftam_error + strlen (ftam_error),
  1071.                 "    type informative");
  1072. #else
  1073.         (void) printf ("    type informative");
  1074. #endif
  1075.         break;
  1076.  
  1077.         case DIAG_TRANS: 
  1078.         didit++;
  1079. #ifdef    BRIDGE
  1080.         (void) sprintf (ftam_error + strlen (ftam_error),
  1081.                 "    type transient");
  1082. #else
  1083.         (void) printf ("    type transient");
  1084. #endif
  1085.         break;
  1086.  
  1087.         case DIAG_PERM: 
  1088.         if (dp -> ftd_observer == EREF_IFSU)
  1089.             ftamfd = NOTOK;
  1090.         if (action != FACTION_SUCCESS)
  1091.             break;
  1092.         didit++;
  1093. #ifdef    BRIDGE
  1094.         (void) sprintf (ftam_error + strlen (ftam_error),
  1095.                 "    type permanent");
  1096. #else
  1097.         (void) printf ("    type permanent");
  1098. #endif
  1099.         break;
  1100.  
  1101.         default: 
  1102.         didit++;
  1103. #ifdef    BRIDGE
  1104.         (void) sprintf (ftam_error + strlen (ftam_error),
  1105.                 "    type %d", dp -> ftd_type);
  1106. #else
  1107.         (void) printf ("    type %d", dp -> ftd_type);
  1108. #endif
  1109.         break;
  1110.     }
  1111.  
  1112.     switch (dp -> ftd_observer) {
  1113.         case EREF_IFSU: 
  1114.         goto print_it;
  1115.  
  1116.         case EREF_IFPM: 
  1117.         if (peer)
  1118.             goto print_it;
  1119.         break;
  1120.  
  1121.         case EREF_RFSU: 
  1122.         if (peer)
  1123.             break;    /* else fall */
  1124.         case EREF_RFPM: 
  1125.     print_it: ;
  1126. #ifdef    BRIDGE
  1127.         (void) sprintf (ftam_error + strlen (ftam_error),
  1128.                 "%sobserver %s", didit++ ? ", " : "    ",
  1129.                 entity[dp -> ftd_observer]);
  1130. #else
  1131.         (void) printf ("%sobserver %s", didit++ ? ", " : "    ",
  1132.             entity[dp -> ftd_observer]);
  1133. #endif
  1134.         break;
  1135.  
  1136.         default: 
  1137. #ifdef    BRIDGE
  1138.         (void) sprintf (ftam_error + strlen (ftam_error),
  1139.                 "%sobserver %d", didit++ ? ", " : "    ",
  1140.                 dp -> ftd_observer);
  1141. #else
  1142.         (void) printf ("%sobserver %d", didit++ ? ", " : "    ",
  1143.             dp -> ftd_observer);
  1144. #endif
  1145.         break;
  1146.     }
  1147.  
  1148.     switch (dp -> ftd_source) {
  1149.         case EREF_NONE: 
  1150.         case EREF_IFSU: 
  1151.         break;
  1152.  
  1153.         case EREF_SERV: 
  1154.         case EREF_RFSU: 
  1155.         if (peer)
  1156.             break;    /* else fall */
  1157.         case EREF_IFPM: 
  1158.         case EREF_RFPM: 
  1159. #ifdef    BRIDGE
  1160.         (void) sprintf (ftam_error + strlen (ftam_error),
  1161.                 "%ssource %s", didit++ ? ", " : "    ",
  1162.                 entity[dp -> ftd_source]);
  1163. #else
  1164.         (void) printf ("%ssource %s", didit++ ? ", " : "    ",
  1165.             entity[dp -> ftd_source]);
  1166. #endif
  1167.         break;
  1168.  
  1169.         default: 
  1170. #ifdef    BRIDGE
  1171.         (void) sprintf (ftam_error + strlen (ftam_error),
  1172.                 "%ssource %d", didit++ ? ", " : "    ",
  1173.                 dp -> ftd_source);
  1174. #else
  1175.         (void) printf ("%ssource %d", didit++ ? ", " : "    ",
  1176.             dp -> ftd_source);
  1177. #endif
  1178.         break;
  1179.     }
  1180.  
  1181.     if (dp -> ftd_delay != DIAG_NODELAY)
  1182. #ifdef    BRIDGE
  1183.         (void) sprintf (ftam_error + strlen (ftam_error),
  1184.                 "%ssuggested-delay %d", didit++ ? ", " : "    ",
  1185.                 dp -> ftd_delay);
  1186. #else
  1187.         (void) printf ("%ssuggested-delay %d", didit++ ? ", " : "    ",
  1188.             dp -> ftd_delay);
  1189. #endif
  1190.  
  1191. #ifndef    BRIDGE
  1192.     if (didit)
  1193.         (void) printf ("\n");
  1194. #endif
  1195.     }
  1196. #ifdef    BRIDGE
  1197.     if (ftam_error[0])
  1198.     advise (NULLCP, "%s", ftam_error);
  1199. #endif
  1200. }
  1201.  
  1202. /*     MISCELLANY */
  1203.  
  1204. rcinit ()
  1205. {
  1206. #ifndef    BRIDGE
  1207.     register int    w;
  1208.     register char **cp;
  1209.     register struct dispatch   *ds;
  1210.     register struct var *v;
  1211. #endif
  1212.     register struct isodocument *id;
  1213.     register struct vfsmap *vf;
  1214.  
  1215. #ifndef    BRIDGE
  1216.     if ((myhome = getenv ("HOME")) == NULL)
  1217.     myhome = ".";        /* could do passwd search... */
  1218.  
  1219.     if ((myuser = getenv ("USER")) == NULLCP)
  1220.     myuser = getenv ("LOGNAME");
  1221. #endif
  1222.  
  1223.     for (vf = vfs + 1; vf -> vf_entry; vf++)  { /* skip "default" entry */
  1224.     if (id = getisodocumentbyentry (vf -> vf_entry)) {
  1225.         if ((vf -> vf_oid = oid_cpy (id -> id_type)) == NULLOID)
  1226.         adios (NULLCP, "out of memory");
  1227. #ifdef COMPAT_OLD_NBS9OID
  1228. #ifdef DEBUG
  1229.         if ((vf -> vf_flags & VF_ALIASED) && watch)
  1230.         advise (NULLCP,
  1231.             "warning: local realstore will support aliasing of %ss (%s)",
  1232.             vf -> vf_text, vf -> vf_entry);
  1233. #endif    /* DEBUG */
  1234. #endif    /* COMPAT_OLD_NBS9OID */
  1235.     }
  1236.     else
  1237.         if (vf -> vf_flags & VF_WARN)
  1238.         advise (NULLCP,
  1239.             "warning: local realstore has no support for %ss (%s)",
  1240.             vf -> vf_text, vf -> vf_entry);
  1241.     }
  1242.     bzero ((char *) &myqos, sizeof myqos);
  1243.     myqos.qos_sversion = 2;
  1244.  
  1245. #ifndef    BRIDGE
  1246.     for (ds = dispatches, helpwidth = 0; ds -> ds_name; ds++)
  1247.     if ((w = strlen (ds -> ds_name)) > helpwidth)
  1248.         helpwidth = w;
  1249.  
  1250.     userdn = strdup ("");
  1251.     for (v = vars, varwidth1 = 0; v -> v_name; v++) {
  1252.     if ((w = strlen (v -> v_name)) > varwidth1)
  1253.         varwidth1 = w;
  1254.  
  1255.     if (v -> v_value) {
  1256.         if (cp = v -> v_dvalue) {
  1257.         if (v -> v_mask) {
  1258. #ifdef    notdef
  1259.             w = 1;
  1260.             while (*++cp)
  1261.             w <<= 1;
  1262.             w--;
  1263.             if ((w = strlen (sprintb (w, v -> v_mask))) > varwidth2)
  1264.             varwidth2 = w;
  1265. #endif
  1266.         }
  1267.         else
  1268.             for (; *cp; cp++)
  1269.             if ((w = strlen (*cp)) > varwidth2)
  1270.                 varwidth2 = w;
  1271.         }
  1272.     }
  1273.     else
  1274.         if (*v -> v_dvalue) {
  1275.         *v -> v_dvalue = strdup (*v -> v_dvalue);
  1276.         if ((w = strlen (*v -> v_dvalue) + 2) > varwidth2)
  1277.             varwidth2 = w;
  1278.         }
  1279.     }
  1280. #endif
  1281. }
  1282.  
  1283.  
  1284. #ifndef    TIOCGWINSZ
  1285. /* ARGSUSED */
  1286. #endif
  1287.  
  1288. int    ncols (fp)
  1289. FILE *fp;
  1290. {
  1291. #ifdef    TIOCGWINSZ
  1292.     int        i;
  1293.     struct winsize ws;
  1294.  
  1295.     if (ioctl (fileno (fp), TIOCGWINSZ, (char *) &ws) != NOTOK
  1296.         && (i = ws.ws_col) > 0)
  1297.     return i;
  1298. #endif
  1299.  
  1300.     return 80;
  1301. }
  1302.  
  1303. /*   */
  1304.  
  1305. #ifndef    NBBY
  1306. #define    NBBY    8
  1307. #endif
  1308.  
  1309.  
  1310. #ifndef    TMS
  1311. timer (cc, action)
  1312. int     cc;
  1313. char   *action;
  1314. {
  1315.     long    ms;
  1316.     float   bs;
  1317.     struct timeval  stop,
  1318.                     td;
  1319.     static struct timeval   start;
  1320.  
  1321.     if (cc == 0) {
  1322.     (void) gettimeofday (&start, (struct timezone *) 0);
  1323.     return;
  1324.     }
  1325.     else
  1326.     (void) gettimeofday (&stop, (struct timezone  *) 0);
  1327.  
  1328.     tvsub (&td, &stop, &start);
  1329.     ms = (td.tv_sec * 1000) + (td.tv_usec / 1000);
  1330.     bs = (((float) cc * NBBY * 1000) / (float) (ms ? ms : 1)) / NBBY;
  1331.  
  1332.     advise (NULLCP, "%d bytes %s in %d.%02d seconds (%.2f Kbytes/s)",
  1333.         cc, action, td.tv_sec, td.tv_usec / 10000, bs / 1024);
  1334. }
  1335.  
  1336.  
  1337. static  tvsub (tdiff, t1, t0)
  1338. register struct timeval *tdiff,
  1339.             *t1,
  1340.             *t0;
  1341. {
  1342.  
  1343.     tdiff -> tv_sec = t1 -> tv_sec - t0 -> tv_sec;
  1344.     tdiff -> tv_usec = t1 -> tv_usec - t0 -> tv_usec;
  1345.     if (tdiff -> tv_usec < 0)
  1346.     tdiff -> tv_sec--, tdiff -> tv_usec += 1000000;
  1347. }
  1348.  
  1349. #else
  1350. #ifndef    HZ
  1351. #define    HZ    60
  1352. #endif
  1353.  
  1354.  
  1355. long    times ();
  1356.  
  1357.  
  1358. timer (cc, action)
  1359. int    cc;
  1360. char   *action;
  1361. {
  1362.     long    ms;
  1363.     float   bs;
  1364.     long    stop,
  1365.         td,
  1366.         secs,
  1367.         msecs;
  1368.     struct tms tm;
  1369.     static long start;
  1370.  
  1371.     if (cc == 0) {
  1372.     start = times (&tm);
  1373.     return;
  1374.     }
  1375.     else
  1376.     stop = times (&tm);
  1377.  
  1378.     td = stop - start;
  1379.     secs = td / HZ, msecs = (td % HZ) * 1000 / HZ;
  1380.     ms = (secs * 1000) +  msecs;
  1381.     bs = (((float) cc * NBBY * 1000) / (float) (ms ? ms : 1)) / NBBY;
  1382.     
  1383.     advise (NULLCP, "%d bytes %s in %d.%02d seconds (%.2f Kbytes/s)",
  1384.         cc, action, secs, msecs / 10, bs / 1024);
  1385. }
  1386. #endif
  1387.  
  1388. /*   */
  1389.  
  1390. #ifdef    BRIDGE
  1391. /* FTP TYPE Function */
  1392.  
  1393. #include <arpa/ftp.h>
  1394.  
  1395. f_type (mode)
  1396. int    mode;
  1397. {
  1398.     switch(mode) {
  1399.         case TYPE_A:
  1400.         tmode = VFS_UTF;
  1401.         return OK;
  1402.         
  1403.     case TYPE_I:
  1404.     case TYPE_L:
  1405.         tmode = VFS_UBF;
  1406.         return OK;
  1407.         
  1408.     case TYPE_E:
  1409.     default:
  1410.         return NOTOK;
  1411.     }
  1412. }
  1413. #endif
  1414.